{
 "metadata": {
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.0-final"
  },
  "orig_nbformat": 2,
  "kernelspec": {
   "name": "python3",
   "display_name": "Python 3",
   "language": "python"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2,
 "cells": [
  {
   "source": [
    "# C06. 函数抽象\n",
    "\n"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]\n"
     ]
    }
   ],
   "source": [
    "fibs=[0,1]\n",
    "for i in range(8):\n",
    "    fibs.append(fibs[-2]+fibs[-1])\n",
    "print(fibs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946]\n"
     ]
    }
   ],
   "source": [
    "fibs=[0,1]\n",
    "num=int(input('How many Fibonacci numbers do you want?'))\n",
    "for i in range(num):\n",
    "    fibs.append(fibs[-2]+fibs[-1])\n",
    "print(fibs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987]\n"
     ]
    }
   ],
   "source": [
    "def fibs_fun(num):\n",
    "    fibs=[0,1]\n",
    "    for i in range(num):\n",
    "        fibs.append(fibs[-2]+fibs[-1])\n",
    "    return fibs\n",
    "\n",
    "num=int(input('How many Fibonacci numbers do you want?'))\n",
    "print(fibs_fun(num))"
   ]
  },
  {
   "source": [
    "## 6.2 抽象 与 结构\n",
    "\n",
    "抽象是程序能够被人理解的关键。"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "source": [
    "## 6.3 自定义函数"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "callable(x)= False\ncallable(y)= True\n"
     ]
    }
   ],
   "source": [
    "import math\n",
    "x=1\n",
    "y=math.sqrt\n",
    "print(\"callable(x)=\",callable(x))\n",
    "print(\"callable(y)=\",callable(y))"
   ]
  },
  {
   "source": [
    "### 6.3.1 给函数编写文档"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "计算 x 的平方\n------------help()------------\nHelp on function square in module __main__:\n\nsquare(x)\n    计算 x 的平方\n\n"
     ]
    }
   ],
   "source": [
    "def square(x):\n",
    "    '计算 x 的平方'\n",
    "    return x*x\n",
    "\n",
    "print(square.__doc__)\n",
    "print(\"help()\".center(30,'-'))\n",
    "help(square)"
   ]
  },
  {
   "source": [
    "### 6.3.2 没有返回值的函数\n",
    "\n",
    "所有的定义都是函数，没有返回值的函数返回值为 None。"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "This is printed\n--------------x---------------\nx= None\n"
     ]
    }
   ],
   "source": [
    "def test():\n",
    "    print(\"This is printed\")\n",
    "    return\n",
    "    print(\"This can't be seen\")\n",
    "\n",
    "x=test()\n",
    "print('x'.center(30,'-'))\n",
    "print(\"x=\",x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "This is printed\n--------------x---------------\nx= None\n"
     ]
    }
   ],
   "source": [
    "def proc():\n",
    "    print(\"This is printed\")\n",
    "\n",
    "x=proc()\n",
    "print('x'.center(30,'-'))\n",
    "print(\"x=\",x)"
   ]
  },
  {
   "source": [
    "## 6.4 参数"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "source": [
    "### 6.4.1 值\n",
    "\n",
    "在 def 语句中，位于函数名后面的变量称为「形参」，而调用函数时提供的值称为「实参」。"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "source": [
    "### 6.4.2 参数修改"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "name= Mrs. Entity\n"
     ]
    }
   ],
   "source": [
    "def try_to_change(n):\n",
    "    n=\"Mr. Gumby\"\n",
    "\n",
    "# names 的值没有改变\n",
    "name=\"Mrs. Entity\"\n",
    "try_to_change(name)\n",
    "print(\"name=\",name)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "names= ['Mr. Gumby', 'Mrs. Thing']\n"
     ]
    }
   ],
   "source": [
    "def change(n):\n",
    "    n[0]=\"Mr. Gumby\"\n",
    "\n",
    "# names 的值被改变\n",
    "names=[\"Mrs. Entity\", \"Mrs. Thing\"]\n",
    "change(names)\n",
    "print(\"names=\",names)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "name==name1: True\nname is name1: True\nname==name2: True\nname is name2: False\n"
     ]
    }
   ],
   "source": [
    "# 将一个列表赋值两个变量时，两个变量指向相同的列表\n",
    "name=[\"zYx\",\"Tom\"]\n",
    "name1=name\n",
    "name2=name[:]\n",
    "print(\"name==name1:\",name==name1)\n",
    "print(\"name is name1:\",name is name1)\n",
    "print(\"name==name2:\",name==name2)\n",
    "print(\"name is name2:\",name is name2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "MyNames= {'first': {}, 'middle': {}, 'last': {}}\nMyNames= {'first': {'Magnus': ['Magnus Lie Hetland'], 'Zhu': ['Zhu Yuan Xiang']}, 'middle': {'Lie': ['Magnus Lie Hetland'], 'Yuan': ['Zhu Yuan Xiang']}, 'last': {'Hetland': ['Magnus Lie Hetland'], 'Xiang': ['Zhu Yuan Xiang']}}\n------------lookup------------\n['Magnus Lie Hetland']\n"
     ]
    }
   ],
   "source": [
    "# 1. 为什么要修改参数？\n",
    "def init(data):\n",
    "    data['first']={}\n",
    "    data['middle']={}\n",
    "    data['last']={}\n",
    "\n",
    "def lookup(data,label,name):\n",
    "    return data[label].get(name)\n",
    "\n",
    "def store(data, full_name):\n",
    "    names=full_name.split()\n",
    "    if len(names)==2:\n",
    "        names.insert(1,'')\n",
    "    labels='first','middle','last'\n",
    "\n",
    "    for label,name in zip(labels,names):\n",
    "        people=lookup(data,label,name)\n",
    "        if people:\n",
    "            people.append(full_name)\n",
    "        else:\n",
    "            data[label][name]=[full_name]\n",
    "\n",
    "MyNames={}\n",
    "init(MyNames)\n",
    "print(\"MyNames=\",MyNames)\n",
    "store(MyNames,'Magnus Lie Hetland')\n",
    "store(MyNames,\"Zhu Yuan Xiang\")\n",
    "print(\"MyNames=\",MyNames)\n",
    "print('lookup'.center(30,'-'))\n",
    "print(lookup(MyNames,'middle','Lie'))"
   ]
  },
  {
   "source": [
    "### 6.4.3 关键字参数 与 指定默认值\n",
    "\n",
    "前面使用的是位置参数，通过参数的位置顺序来确定传递的值。\n",
    "\n",
    "使用名称指定的参数称为关键字参数，利用参数的名称来确定传递的值。\n",
    "\n",
    "关键字参数可以指定默认值。"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "hello_1()=Hello, world!\nhello_2()=Hello, world!\nhello_3()=Hello, world!\nhello_3()=Hello, Gumby!\n"
     ]
    }
   ],
   "source": [
    "def hello_1(greeting,name):\n",
    "    print(\"{}, {}!\".format(greeting, name))\n",
    "\n",
    "def hello_2(name,greeting):\n",
    "    print(\"{}, {}!\".format(name, greeting))\n",
    "\n",
    "def hello_3(greeting='Hello', name='world'):\n",
    "    print(\"{}, {}!\".format(greeting, name))\n",
    "\n",
    "print(\"hello_1()=\", end='')\n",
    "hello_1('Hello','world')\n",
    "print(\"hello_2()=\", end='')\n",
    "hello_2('Hello','world')\n",
    "print(\"hello_3()=\", end='')\n",
    "hello_3('Hello','world')\n",
    "print(\"hello_3()=\", end='')\n",
    "hello_3(name='Gumby')"
   ]
  },
  {
   "source": [
    "### 6.4.4 收集参数\n",
    "\n",
    "参数前面的一个星号「*」将提供的所有位置参数收集到一个元组中\n",
    "\n",
    "参数前面的两个星号「**」将提供的所有关键字参数收集到一个字典中"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "('Testing',)\n(1, 2, 3)\n(1, 2, 3)\n"
     ]
    }
   ],
   "source": [
    "def print_params(*params):\n",
    "    print(params)\n",
    "\n",
    "print_params('Testing')\n",
    "print_params(1,2,3)\n",
    "print_params(*(1,2,3))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "Params:\n(1, 2, 3)\nNothing:\n()\n"
     ]
    }
   ],
   "source": [
    "def print_params_2(title,*params):\n",
    "    print(title)\n",
    "    print(params)\n",
    "\n",
    "print_params_2(\"Params:\",1,2,3)\n",
    "print_params_2(\"Nothing:\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "1 (2, 3, 4, 5) 7\n"
     ]
    }
   ],
   "source": [
    "def in_the_middle(x,*y,z):\n",
    "    print(x,y,z)\n",
    "\n",
    "in_the_middle(1,2,3,4,5,z=7)\n",
    "# in_the_middle(1,2,3,4,5,7) # 不指定 z 的值，就会因为前面把所有的变量都收集了导致没有值而报错"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "{'x': 1, 'y': (2, 3, 4), 'z': 7}\n"
     ]
    }
   ],
   "source": [
    "def print_params_3(**params):\n",
    "    print(params)\n",
    "\n",
    "print_params_3(x=1,y=(2,3,4),z=7)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "1 2 3\n(4, 5, 6, 7)\n{'foo': 1, 'bar': 2}\n-------------最少参数-------------\n1 2 7\n()\n{}\n"
     ]
    }
   ],
   "source": [
    "def print_params_4(x,y,z=7,*pospar, **keypar):\n",
    "    print(x,y,z)\n",
    "    print(pospar)\n",
    "    print(keypar)\n",
    "\n",
    "print_params_4(1,2,3,4,5,6,7,foo=1,bar=2)\n",
    "print(\"最少参数\".center(30,'-'))\n",
    "print_params_4(1,2,)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [
    {
     "output_type": "execute_result",
     "data": {
      "text/plain": [
       "['Luke Skywalker', 'Anakin Skywalker']"
      ]
     },
     "metadata": {},
     "execution_count": 40
    }
   ],
   "source": [
    "def store(data, *full_names):\n",
    "    for full_name in full_names:\n",
    "        names=full_name.split()\n",
    "        if len(names)==2:\n",
    "            names.insert(1,'')\n",
    "        labels='first','middle','last'\n",
    "        for label,name in zip(labels,names):\n",
    "            people=lookup(data,label,name)\n",
    "            if people:\n",
    "                people.append(full_name)\n",
    "            else:\n",
    "                data[label][name]=[full_name]\n",
    "\n",
    "MyNames={}\n",
    "init(MyNames)\n",
    "store(MyNames,'Han Solo')\n",
    "store(MyNames,'Luke Skywalker','Anakin Skywalker')\n",
    "lookup(MyNames,'last','Skywalker')"
   ]
  },
  {
   "source": [
    "### 6.4.5 分配参数\n",
    "\n",
    "值前面的一个星号「*」，将会把传递的元组或者列表分拆给不同的参数\n",
    "\n",
    "值前面的两个星期「**」，将会把传递的字典分拆给不同的关键字参数"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "3\n"
     ]
    }
   ],
   "source": [
    "def add(x,y):\n",
    "    return x+y\n",
    "\n",
    "params=(1,2)\n",
    "print(add(*params))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "3\n"
     ]
    }
   ],
   "source": [
    "params={'x':1,'y':2}\n",
    "print(add(**params))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "----------with_stars----------\nMr. Gumby is 42 years old\n--------without_stars---------\nMr. Gumby is 42 years old\n"
     ]
    }
   ],
   "source": [
    "def with_stars(**kwds):\n",
    "    print(kwds['name'], 'is', kwds['age'], 'years old')\n",
    "\n",
    "def without_stars(kwds):\n",
    "    print(kwds['name'], 'is', kwds['age'], 'years old')\n",
    "\n",
    "args={'name':\"Mr. Gumby\", 'age':42}\n",
    "print('with_stars'.center(30,'-'))\n",
    "with_stars(**args)\n",
    "print('without_stars'.center(30,'-'))\n",
    "without_stars(args)"
   ]
  },
  {
   "source": [
    "### 6.4.6 使用参数"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "Once upon a time, there was a king called Gumby\nOnce upon a time, there was a brave knight called Sir Robin\nOnce upon a time, there was a language called Python\nOnce upon a time, there was a stroke of genius called Python\n"
     ]
    }
   ],
   "source": [
    "def story(**kwds):\n",
    "    return \"Once upon a time, there was a {job} called {name}\".format_map(kwds)\n",
    "\n",
    "print(story(job='king', name='Gumby'))\n",
    "print(story(name='Sir Robin', job='brave knight'))\n",
    "params={'job':'language', 'name':'Python'}\n",
    "print(story(**params))\n",
    "del params['job']\n",
    "print(story(job='stroke of genius', **params))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "power(2,3)= 8\npower(3,2)= 9\npower(y=3,x=2)= 8\nparams= (5, 5)\npower(*params)= 3125\nReceived redundant parameters: ('Hello, world!',)\npower(3,3, 'Hello, world!') 27\n"
     ]
    }
   ],
   "source": [
    "def power(x,y,*others):\n",
    "    if others:\n",
    "        print(\"Received redundant parameters:\",others)\n",
    "    return pow(x,y)\n",
    "\n",
    "print(\"power(2,3)=\",power(2,3))\n",
    "print(\"power(3,2)=\",power(3,2))\n",
    "print(\"power(y=3,x=2)=\",power(y=3,x=2))\n",
    "params=(5,)*2\n",
    "print(\"params=\",params)\n",
    "print(\"power(*params)=\",power(*params))\n",
    "print(\"power(3,3, 'Hello, world!')=\",power(3,3, 'Hello, world!'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "interval(10)= [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\ninterval(1,5)= [1, 2, 3, 4]\ninterval(3,12,4)= [3, 7, 11]\ninterval(3,7)= [3, 4, 5, 6]\n*interval(3,7)= 3 4 5 6\n----power(*interval(3,7))-----\nReceived redundant parameters: (5, 6)\npower(*interval(3,7))= 81\n"
     ]
    }
   ],
   "source": [
    "def interval(start, stop=None, step=1):\n",
    "    \"Imitates range() for step>0\"\n",
    "    if stop is None:\n",
    "        start, stop=0, start\n",
    "\n",
    "    result=[]\n",
    "    i=start\n",
    "    while i<stop:\n",
    "        result.append(i)\n",
    "        i+=step\n",
    "    return result\n",
    "\n",
    "print(\"interval(10)=\",interval(10))\n",
    "print(\"interval(1,5)=\",interval(1,5))\n",
    "print(\"interval(3,12,4)=\",interval(3,12,4))\n",
    "print(\"interval(3,7)=\",interval(3,7))\n",
    "print(\"*interval(3,7)=\",*interval(3,7))\n",
    "print(\"power(*interval(3,7))\".center(30,'-'))\n",
    "print(\"power(*interval(3,7))=\",power(*interval(3,7)))"
   ]
  },
  {
   "source": [
    "## 6.5 作用域\n",
    "\n",
    "内置函数 vars() 返回一个不可见的字典，这个不可见的字典称为命名空间或者作用域。\n",
    "\n",
    "作用域的个数：除全局作用域外，每个函数调用都将创建一个。"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "1\n"
     ]
    }
   ],
   "source": [
    "x=1\n",
    "scope=vars()\n",
    "print(scope['x'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "42\n1\n"
     ]
    }
   ],
   "source": [
    "def foo(): \n",
    "    x=42\n",
    "    scope=vars()\n",
    "    print(scope['x'])\n",
    "\n",
    "foo()\n",
    "scope=vars()\n",
    "print(scope['x'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "2\n1\n"
     ]
    }
   ],
   "source": [
    "def output(x):\n",
    "    scope=vars()\n",
    "    print(scope['x'])\n",
    "\n",
    "x,y=1,2\n",
    "output(y)\n",
    "scope=vars()\n",
    "print(scope['x'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "3\n2\n1\n"
     ]
    }
   ],
   "source": [
    "def add(y):\n",
    "    print(x+y)\n",
    "    scope=vars()\n",
    "    # print(scope['x']) # 在函数的作用域中无法找到变量 x\n",
    "    print(scope['y'])\n",
    "\n",
    "add(y)\n",
    "scope=vars()\n",
    "print(scope['x'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "3\n2\n1\n"
     ]
    }
   ],
   "source": [
    "def add(y):\n",
    "    global x\n",
    "    print(x+y)\n",
    "    scope=vars()\n",
    "    # print(scope['x']) # 指定为全局变量，在函数的作用域中无法找到变量 x\n",
    "    print(scope['y'])\n",
    "\n",
    "add(y)\n",
    "scope=vars()\n",
    "print(scope['x'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "double(5)= 10\ntriple(5)= 15\nmultiplier(3)(5)= 15\n"
     ]
    }
   ],
   "source": [
    "# 作用域嵌套\n",
    "def multiplier(factor):\n",
    "    def multiplierByFactor(number):\n",
    "        return number * factor\n",
    "    return multiplierByFactor\n",
    "\n",
    "double=multiplier(2)\n",
    "print(\"double(5)=\",double(5))\n",
    "\n",
    "triple=multiplier(3)\n",
    "print(\"triple(5)=\",triple(5))\n",
    "print(\"multiplier(3)(5)=\",multiplier(3)(5))"
   ]
  },
  {
   "source": [
    "如果在一个函数的内部定义了另一个函数，外部的叫外函数，内部的叫内函数。\n",
    "\n",
    "在一个外函数中定义了一个内函数，内函数里运用了外函数的临时变量，并且外函数的返回值是内函数的引用。这样就构成了一个闭包。"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "15\n17\n"
     ]
    }
   ],
   "source": [
    "#闭包函数的实例\n",
    "# outer是外部函数 a和b都是外函数的临时变量\n",
    "def outer(a):\n",
    "    b = 10\n",
    "    # inner是内函数\n",
    "    def inner():\n",
    "        #在内函数中 用到了外函数的临时变量\n",
    "        print(a+b)\n",
    "    # 外函数的返回值是内函数的引用\n",
    "    return inner\n",
    "\n",
    "# 调用外函数传入参数5：外函数两个临时变量 a=5 b=10，并创建内函数\n",
    "# 然后把内函数的引用 返回给 demo，外函数结束时发现内函数将会用到自己的临时变量，这两个临时变量就不会释放，会绑定给这个内函数\n",
    "# 调用内函数，发现内函数可以使用外函数的变量\n",
    "# demo=外函数的返回值，也就是inner函数的引用，这里相当于执行inner函数\n",
    "demo = outer(5)\n",
    "demo() # 15\n",
    "demo2 = outer(7)\n",
    "demo2() #17"
   ]
  },
  {
   "source": [
    "## 6.6 递归\n",
    "\n",
    "递归式函数定义：函数可以调用自己。\n",
    "\n",
    "-   基线条件(针对最小的问题)：满足这种条件时函数将直接返回一个值\n",
    "-   递归条件：包含一个或者多个调用，这些调用旨在解决问题的一部分"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "metadata": {},
   "outputs": [],
   "source": [
    "def recursion():\n",
    "    return recursion()\n",
    "\n",
    "# recursion() # 调用后会导致「递归错误」"
   ]
  },
  {
   "source": [
    "### 6.6.1 经典案例：阶乘"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 72,
   "metadata": {},
   "outputs": [
    {
     "output_type": "execute_result",
     "data": {
      "text/plain": [
       "3628800"
      ]
     },
     "metadata": {},
     "execution_count": 72
    }
   ],
   "source": [
    "def factorial(n):\n",
    "    \"循环实现阶乘\"\n",
    "    result=n\n",
    "    for i in range(1,n):\n",
    "        result*=i\n",
    "    return result\n",
    "\n",
    "factorial(10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 73,
   "metadata": {},
   "outputs": [
    {
     "output_type": "execute_result",
     "data": {
      "text/plain": [
       "3628800"
      ]
     },
     "metadata": {},
     "execution_count": 73
    }
   ],
   "source": [
    "def factorial(n):\n",
    "    \"递归实现阶乘\"\n",
    "    if n==1:\n",
    "        return 1\n",
    "    else:\n",
    "        return n*factorial(n-1)\n",
    "\n",
    "factorial(10)"
   ]
  },
  {
   "source": [
    "### 6.6.1 经典案例：幂"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 76,
   "metadata": {},
   "outputs": [
    {
     "output_type": "execute_result",
     "data": {
      "text/plain": [
       "27"
      ]
     },
     "metadata": {},
     "execution_count": 76
    }
   ],
   "source": [
    "def power(x,n):\n",
    "    \"循环实现幂\"\n",
    "    result=1\n",
    "    for i in range(n):\n",
    "        result*=x\n",
    "    return result\n",
    "\n",
    "power(3,3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 77,
   "metadata": {},
   "outputs": [
    {
     "output_type": "execute_result",
     "data": {
      "text/plain": [
       "27"
      ]
     },
     "metadata": {},
     "execution_count": 77
    }
   ],
   "source": [
    "def power(x,n):\n",
    "    \"递归实现幂\"\n",
    "    if n==0:\n",
    "        return 1\n",
    "    else:\n",
    "        return x*power(x,n-1)\n",
    "\n",
    "power(3,3)"
   ]
  },
  {
   "source": [
    "### 6.6.2 经典案例：二分查找"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 86,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "seq= [4, 8, 34, 67, 95, 100, 123]\nsearch(seq,34,1,4)= 2\nCan't find the number:34\nsearch(seq,34,4,6)= None\nCan't find the number:34\nsearch(seq,34,4,16)= None\n"
     ]
    }
   ],
   "source": [
    "def search(sequence, number, lower=0, upper=None):\n",
    "    if (upper is None) or (upper > len(sequence)-1):\n",
    "        upper=len(sequence)-1\n",
    "    if lower==upper:\n",
    "        if number != sequence[upper]:\n",
    "            print(\"Can't find the number:{}\".format(number))\n",
    "            return None\n",
    "        return upper\n",
    "    else:\n",
    "        middle=(lower+upper)//2\n",
    "        if number > sequence[middle]:\n",
    "            return search(sequence,number,middle+1,upper)\n",
    "        else:\n",
    "            return search(sequence,number,lower,middle)\n",
    "\n",
    "seq=[34,67,8,123,4,100,95]\n",
    "seq.sort()\n",
    "print(\"seq=\",seq)\n",
    "print(\"search(seq,34,1,4)=\",search(seq,34,1,4))\n",
    "print(\"search(seq,34,4,6)=\",search(seq,34,4,6))\n",
    "print(\"search(seq,34,4,16)=\",search(seq,34,4,16))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 91,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "list(map(str,range(10)))= ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']\n[str(i) for i in range(10)]= ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']\n"
     ]
    }
   ],
   "source": [
    "# 函数式编程：支持此类编程的函数 map, filter, reduce\n",
    "print(\"list(map(str,range(10)))=\",list(map(str,range(10))))\n",
    "print(\"[str(i) for i in range(10)]=\",[str(i) for i in range(10)])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 92,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "list(filter(func,seq))= ['foo', 'x41']\n[x for x in seq if x.isalnum()]= ['foo', 'x41']\n"
     ]
    }
   ],
   "source": [
    "def func(x):\n",
    "    return x.isalnum() # 检测字符串是否由字母和数字组成。\n",
    "\n",
    "seq=['foo','x41','?!','***']\n",
    "print(\"list(filter(func,seq))=\",list(filter(func,seq)))\n",
    "print(\"[x for x in seq if x.isalnum()]=\",[x for x in seq if x.isalnum()])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 95,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "list(filter(lambda x:x.isalnum(), seq))= ['foo', 'x41']\n"
     ]
    }
   ],
   "source": [
    "# 函数式编程：lambda 表达式\n",
    "seq=['foo','x41','?!','***']\n",
    "print(\"list(filter(lambda x:x.isalnum(), seq))=\",list(filter(lambda x:x.isalnum(), seq)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 101,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "6\n"
     ]
    }
   ],
   "source": [
    "from functools import reduce\n",
    "numbers=range(1,4)\n",
    "print(reduce(lambda x,y:x+y,numbers))"
   ]
  },
  {
   "source": [
    "## 6.7 小结\n",
    "\n",
    "-   抽象：隐藏不必要的细节。通过定义处理细节的函数，使得程序更加抽象。\n",
    "-   函数定义：使用 def 语句。函数由语句块组成，从外部接受值(参数)，并且可能返回一个或者多个值(计算结果)。\n",
    "-   参数：函数通过参数(调用函数时被设置的变量)接收所需的信息。\n",
    "    -   参数共有两类：位置参数 与 关键字参数。\n",
    "    -   通过给参数指定默认值，使其变成可选的。\n",
    "-   作用域：变量存储在作用域(也叫命名空间)中。\n",
    "    -   作用域共有两类：全局作用域 与 局部作用域。\n",
    "    -   作用域可以嵌套。\n",
    "-   递归：函数调用自身的方式。使用递归完成的任何任务都可以使用循环来替换。某些时候递归函数可以提高可读性。\n",
    "-   函数式编程：lambda 表达式，函数 map, filter, reduce\n"
   ],
   "cell_type": "markdown",
   "metadata": {}
  }
 ]
}